Process for whole- model testing

f_dmrs <- fread("/home1/NEURO/SHARE_DECIPHER/DMRs/TERRE/sig.cpgs.TERRE.F.HT.ancestry.csv")[abs(meanbetafc) >= 0.03]
m_dmrs <- fread("/home1/NEURO/SHARE_DECIPHER/DMRs/TERRE/sig.cpgs.TERRE.M.HT.ancestry.csv")[abs(meanbetafc) >= 0.03]
males_pd <- rbindlist(
  lapply(
    Sys.glob("male_terre_pd_f_*_dnam_breakdown.txt.gz"),
    function(f) fread(f, fill = TRUE)),
  fill = TRUE
)[cpg %in% m_dmrs$cpg]
males_pd[, `:=`(f_q=p.adjust(f_p, method = "BH")), by = c("model", "env")]
females_pd <- rbindlist(
  lapply(
    Sys.glob("female_terre_pd_f_*_dnam_breakdown.txt.gz"),
    function(f) fread(f, fill = TRUE)),
  fill = TRUE)[cpg %in% f_dmrs$cpg]
females_pd[, `:=`(f_q=p.adjust(f_p, method = "BH")), by = c("model", "env")]

Filtering data by:

males_pd_sig <- males_pd[f_q < 0.05]
females_pd_sig <- females_pd[f_q < 0.05]

aic ranking

males_aic <- males_pd_sig[,.SD[which.min(aic)],by="cpg"]
females_aic <- females_pd_sig[,.SD[which.min(aic)],by="cpg"]
males_aic[m_dmrs,on=.(cpg)]
females_aic[f_dmrs,on=.(cpg)]
males_aic$Sex <- "Male"
females_aic$Sex <- "Female"
ggplot(rbind(males_aic,females_aic), aes(model,fill=Sex)) +
  geom_bar(position="dodge")+
  geom_text(stat="count",aes(label = ..count..),position=position_dodge(width=0.9),vjust=0)+
  scale_fill_manual(values=c("Male"="lightblue2","Female"="pink"))+
  theme_minimal()

f_dmrs$Sex <- "Female"
m_dmrs$Sex <- "Male"
all_dmr <- rbind(m_dmrs,f_dmrs)
all_aic <- rbind(males_aic, females_aic)
to_plot <- all_aic[all_dmr,on=.(cpg,Sex),nomatch=0]
ggplot(to_plot[!duplicated(paste0(dmr,model,Sex))], aes(model,fill=Sex)) +
  geom_bar(position="dodge")+
  geom_text(stat="count",aes(label = ..count..),position=position_dodge(width=0.9),vjust=0)+
  scale_fill_manual(values=c("Male"="lightblue2","Female"="pink"))+
  theme_minimal()

Effect size comparisons

Take all significant models, compare G vs E vs GxE effect sizes:

males_pd_sig[,.(.N,uniqueN(cpg)),by="model"]
females_pd_sig[,.(.N,uniqueN(cpg)),by="model"]
plt <- VennDiagram::venn.diagram(
  lapply(split(males_pd_sig,by="model"),function(dt)dt$cpg),
  filename=NULL
)
grid::grid.newpage()
grid::grid.draw(plt)


plt <- VennDiagram::venn.diagram(
  lapply(split(females_pd_sig,by="model"),function(dt)dt$cpg),
  filename=NULL
)
grid::grid.newpage()
grid::grid.draw(plt)


plt <- VennDiagram::venn.diagram(
  lapply(split(males_pd_sig,by="model"),function(dt)dt$SNP),
  filename=NULL
)
grid::grid.newpage()
grid::grid.draw(plt)


plt <- VennDiagram::venn.diagram(
  lapply(split(females_pd_sig,by="model"),function(dt)dt$SNP),
  filename=NULL
)
grid::grid.newpage()
grid::grid.draw(plt)

Effects in GxE set

library(ggpubr)
gxe_males_pd <- males_pd[model=="GxE"]
gxe_males_pd[, `:=`(G_q=p.adjust(Gp,method="fdr"),E_q=p.adjust(Ep,method="fdr"),GxE_q=p.adjust(GxEp,method="fdr")),by=c("env")]
gxe_males_pd <- gxe_males_pd[f_q < 0.05]

gxe_males_pd[,.(uniqueN(cpg[G_q < 0.05]),uniqueN(cpg[E_q < 0.05]),uniqueN(cpg[GxE_q < 0.05]))]
gxe_male_sig_G_count <- table(gxe_males_pd[G_q < 0.05][,.(cpg,env)]) # counts of SNPs with significant effects per cpg,env

gxe_males_pd[G_q < 0.05][!duplicated(cpg)]
sig_male_e <- gxe_males_pd[E_q < 0.05]
sig_male_e[!duplicated(sig_male_e[,.(env,cpg)])]

gxe_females_pd <- females_pd[model=="GxE"]
gxe_females_pd[, `:=`(G_q=p.adjust(Gp,method="fdr"),E_q=p.adjust(Ep,method="fdr"),GxE_q=p.adjust(GxEp,method="fdr")),by=c("env")]
gxe_females_pd <- gxe_females_pd[f_q < 0.05]

gxe_females_pd[,.(uniqueN(cpg[G_q < 0.05]),uniqueN(cpg[E_q < 0.05]),uniqueN(cpg[GxE_q < 0.05]))]
gxe_female_sig_G_count <- table(gxe_females_pd[G_q < 0.05][,.(cpg,env)]) # counts of SNPs with significant effects per cpg,env

gxe_females_pd[G_q < 0.05][!duplicated(cpg)]
gxe_females_pd[E_q < 0.05]
NA
ggboxplot(
  melt(gxe_males_pd[,.SD[which.min(aic)],by="cpg"][,.(G=abs(Gest),E=abs(Eest),GxE=abs(GxEest))],value.name="Estimate",variable.name = "Coefficient"),x = "Coefficient",y="Estimate",outlier.shape = NA,fill = "lightblue2") +
  coord_cartesian(ylim=c(0,1)) +
  stat_compare_means(
    paired=TRUE,label.y = -0.5,method.args = list(alternative ="g"),tip.length = 0.01, step.increase = 0.012,
    comparisons = list(c("G","E"),c("G","GxE"),c("E","GxE")))
id.vars and measure.vars are internally guessed when both are 'NULL'. All non-numeric/integer/logical type columns are considered id.vars, which in this case are columns []. Consider providing at least one of 'id' or 'measure' vars in future.

compare_means(
  Estimate~Coefficient,paired=TRUE,
  melt(gxe_males_pd[,.SD[which.min(aic)],by="cpg"][,.(G=abs(Gest),E=abs(Eest),GxE=abs(GxEest))],value.name="Estimate",variable.name = "Coefficient"),
  alternative="l",method = "wilcox") 
id.vars and measure.vars are internally guessed when both are 'NULL'. All non-numeric/integer/logical type columns are considered id.vars, which in this case are columns []. Consider providing at least one of 'id' or 'measure' vars in future.
kruskal.test(melt(gxe_males_pd[,.SD[which.min(aic)],by="cpg"][,.(G=abs(Gest),E=abs(Eest),GxE=abs(GxEest))],value.name="Estimate",variable.name = "Coefficient"))
id.vars and measure.vars are internally guessed when both are 'NULL'. All non-numeric/integer/logical type columns are considered id.vars, which in this case are columns []. Consider providing at least one of 'id' or 'measure' vars in future.some elements of 'x' are not numeric and will be coerced to numeric

    Kruskal-Wallis rank sum test

data:  melt(gxe_males_pd[, .SD[which.min(aic)], by = "cpg"][, .(G = abs(Gest),     E = abs(Eest), GxE = abs(GxEest))], value.name = "Estimate",     variable.name = "Coefficient")
Kruskal-Wallis chi-squared = 200.47, df = 1, p-value < 2.2e-16
ggboxplot(
  melt(gxe_females_pd[,.SD[which.min(aic)],by="cpg"][,.(G=abs(Gest),E=abs(Eest),GxE=abs(GxEest))],value.name="Estimate",variable.name = "Coefficient"),x = "Coefficient",y="Estimate",outlier.shape=NA,fill = "pink") +
  coord_cartesian(ylim=c(0,1.5)) +
  stat_compare_means(paired=TRUE,label.y = -14.,method.args = list(alternative ="l"),tip.length = 0.0005,step.increase=0.0006,comparisons = list(c("G","E"),c("G","GxE"),c("E","GxE")))
id.vars and measure.vars are internally guessed when both are 'NULL'. All non-numeric/integer/logical type columns are considered id.vars, which in this case are columns []. Consider providing at least one of 'id' or 'measure' vars in future.

compare_means(Estimate~Coefficient,paired=TRUE,melt(gxe_females_pd[,.SD[which.min(aic)],by="cpg"][,.(G=abs(Gest),E=abs(Eest),GxE=abs(GxEest))],value.name="Estimate",variable.name = "Coefficient"),alternative="g") 
id.vars and measure.vars are internally guessed when both are 'NULL'. All non-numeric/integer/logical type columns are considered id.vars, which in this case are columns []. Consider providing at least one of 'id' or 'measure' vars in future.
kruskal.test(melt(gxe_females_pd[,.SD[which.min(aic)],by="cpg"][,.(G=abs(Gest),E=abs(Eest),GxE=abs(GxEest))],value.name="Estimate",variable.name = "Coefficient"))
id.vars and measure.vars are internally guessed when both are 'NULL'. All non-numeric/integer/logical type columns are considered id.vars, which in this case are columns []. Consider providing at least one of 'id' or 'measure' vars in future.some elements of 'x' are not numeric and will be coerced to numeric

    Kruskal-Wallis rank sum test

data:  melt(gxe_females_pd[, .SD[which.min(aic)], by = "cpg"][, .(G = abs(Gest),     E = abs(Eest), GxE = abs(GxEest))], value.name = "Estimate",     variable.name = "Coefficient")
Kruskal-Wallis chi-squared = 617.77, df = 1, p-value < 2.2e-16

scale of differences per model @TODO GxE

gxe_males_pd[,`:=`(Zge = (abs(Gest) - abs(Eest))/sqrt(Gse^2 + Ese^2))]
gxe_males_pd[,`:=`(Zp = 2*(pnorm(-abs(Zge))))]
gxe_males_pd[,`:=`(Z_q = p.adjust(Zp,method="fdr")),by=c("env")]

gxe_males_pd[,`:=`(Zgxe = (abs(Gest) - abs(GxEest))/sqrt(Gse^2 + GxEse^2))]
gxe_males_pd[,`:=`(Zgxep = 2*(pnorm(-abs(Zgxe))))]
gxe_males_pd[,`:=`(Zgxe_q = p.adjust(Zgxep,method="fdr")),by=c("env")]

gxe_males_pd[,`:=`(Zegxe = (abs(Eest) - abs(GxEest))/sqrt(Ese^2 + GxEse^2))]
gxe_males_pd[,`:=`(Zegxep = 2*(pnorm(-abs(Zegxe))))]
gxe_males_pd[,`:=`(Zegxe_q = p.adjust(Zegxep,method="fdr")),by=c("env")]

gxe_females_pd[,`:=`(Zge = (abs(Gest) - abs(Eest))/sqrt(Gse^2 + Ese^2))]
gxe_females_pd[,`:=`(Zp = 2*(pnorm(-abs(Zge))))]
gxe_females_pd[,`:=`(Z_q = p.adjust(Zp,method="fdr")),by=c("env")]

gxe_females_pd[,`:=`(Zgxe = (abs(Gest) - abs(GxEest))/sqrt(Gse^2 + GxEse^2))]
gxe_females_pd[,`:=`(Zgxep = 2*(pnorm(-abs(Zgxe))))]
gxe_females_pd[,`:=`(Zgxe_q = p.adjust(Zgxep,method="fdr")),by=c("env")]

gxe_females_pd[,`:=`(Zegxe = (abs(Eest) - abs(GxEest))/sqrt(Ese^2 + GxEse^2))]
gxe_females_pd[,`:=`(Zegxep = 2*(pnorm(-abs(Zegxe))))]
gxe_females_pd[,`:=`(Zegxe_q = p.adjust(Zegxep,method="fdr")),by=c("env")]
gxe_males_pd[Z_q < 0.05,.(hits=uniqueN(cpg),paste0(unique(cpg),collapse=",")),by="env"]
gxe_females_pd[Z_q < 0.05,.(hits=uniqueN(cpg),paste0(unique(cpg),collapse=",")),by="env"]
gxe_males_pd[Z_q < 0.05]
gxe_females_pd[Z_q < 0.05]
unique(gxe_males_pd[Z_q < 0.05]$cpg)
 [1] "cg11381759" "cg23034985" "cg05184729" "cg05903289" "cg05962382" "cg22307029" "cg24324837" "cg05388281" "cg10197305" "cg12717203" "cg14192029" "cg19819404" "cg20320494"
[14] "cg21149944" "cg22831726" "cg10464773" "cg18403080" "cg18405330"
unique(gxe_females_pd[Z_q < 0.05]$cpg)
[1] "cg00687962" "cg18041640" "cg25243082"
m_dmrs[cpg %in% unique(gxe_males_pd[Z_q < 0.05]$cpg)]
f_dmrs[cpg %in% unique(gxe_females_pd[Z_q < 0.05]$cpg)]
gxe_males_pd[Zgxe_q < 0.05,.(hits=uniqueN(cpg),paste0(unique(cpg),collapse=",")),by="env"]
gxe_females_pd[Zgxe_q < 0.05,.(hits=uniqueN(cpg),paste0(unique(cpg),collapse=",")),by="env"]
gxe_males_pd[Zgxe_q < 0.05]
gxe_females_pd[Zgxe_q < 0.05]
unique(gxe_males_pd[Zgxe_q < 0.05]$cpg)
 [1] "cg11381759" "cg23034985" "cg02645135" "cg02612332" "cg08433999" "cg10507346" "cg07278634" "cg08285289" "cg05903289" "cg05962382" "cg22307029" "cg24324837" "cg07594247"
[14] "cg07772999" "cg11763394" "cg17445212" "cg19083407" "cg21482265" "cg21550016" "cg23122642" "cg05388281" "cg10197305" "cg12717203" "cg14192029" "cg19819404" "cg20320494"
[27] "cg21149944" "cg22831726" "cg04265523" "cg10464773" "cg18403080" "cg18405330"
unique(gxe_females_pd[Zgxe_q < 0.05]$cpg)
 [1] "cg09767236" "cg09499504" "cg14341378" "cg17662445" "cg06699216" "cg00687962" "cg04399643" "cg18041640" "cg25243082" "cg05841700" "cg07157834" "cg07167872" "cg07533224"
[14] "cg11965913" "cg12898220" "cg14159672" "cg14893161" "cg16334093" "cg17178900" "cg24503407" "cg26354017" "cg05432213" "cg20803293" "cg20331612" "cg26191422" "cg16787483"
[27] "cg12045875" "cg00290607" "cg14500267" "cg14942906" "cg23188684" "cg24690094" "cg16786756" "cg01485177" "cg24598948" "cg00588198" "cg03198009" "cg03449857" "cg04071440"
[40] "cg07134666" "cg08022281" "cg10648573" "cg11383134" "cg11747594" "cg12644888" "cg13835168" "cg15570656" "cg15708526" "cg16885113" "cg19636627" "cg20228636" "cg22494932"
[53] "cg24100841" "cg25699073" "cg25978138"
m_dmrs[cpg %in% unique(gxe_males_pd[Zgxe_q < 0.05]$cpg)]
f_dmrs[cpg %in% unique(gxe_females_pd[Zgxe_q < 0.05]$cpg)]
gxe_males_pd[Zegxe_q < 0.05,.(hits=uniqueN(cpg),paste0(unique(cpg),collapse=",")),by="env"]
gxe_females_pd[Zegxe_q < 0.05,.(hits=uniqueN(cpg),paste0(unique(cpg),collapse=",")),by="env"]
gxe_males_pd[Zegxe_q < 0.05]
gxe_females_pd[Zegxe_q < 0.05]
unique(gxe_males_pd[Zegxe_q < 0.05]$cpg)
character(0)
unique(gxe_females_pd[Zegxe_q < 0.05]$cpg)
character(0)
m_dmrs[cpg %in% unique(gxe_males_pd[Zegxe_q < 0.05]$cpg)]
f_dmrs[cpg %in% unique(gxe_females_pd[Zegxe_q < 0.05]$cpg)]
ggboxplot(rbindlist(list(Male=gxe_males_pd[,.(Zge)],Female=gxe_females_pd[,.(Zge)]),idcol="Sex"),x="Sex",y="Zge",fill="Sex") +
  scale_fill_manual(values=c(Male = "lightblue2", Female="pink")) +
  stat_compare_means()


ggboxplot(rbindlist(list(Male=gxe_males_pd[,.(Zgxe)],Female=gxe_females_pd[,.(Zgxe)]),idcol="Sex"),x="Sex",y="Zgxe",fill="Sex") +
  scale_fill_manual(values=c(Male = "lightblue2", Female="pink")) +
  stat_compare_means()


ggboxplot(rbindlist(list(Male=gxe_males_pd[,.(Zegxe)],Female=gxe_females_pd[,.(Zegxe)]),idcol="Sex"),x="Sex",y="Zegxe",fill="Sex") +
  scale_fill_manual(values=c(Male = "lightblue2", Female="pink")) +
  stat_compare_means()

LS0tCnRpdGxlOiAiQ2xlYW4gdGVycmUgRE1SIGJyZWFrZG93biIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9CmxpYnJhcnkoZHBseXIpCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShkYXRhLnRhYmxlKQpTeXMuc2V0bG9jYWxlKCJMQ19NRVNTQUdFUyIsICJlbl9VUy51dGY4IikKa25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFLCBjYWNoZSA9IEZBTFNFLCBldmFsID0gVFJVRSwgYXV0b2RlcCA9IFRSVUUpCmBgYAoKIyBQcm9jZXNzIGZvciB3aG9sZS0gbW9kZWwgdGVzdGluZwotIFN0ZXAgMTogcmVhZCBpbiBkYXRhLCBydW4gbXVsdGlwbGUgdGVzdCBjb3JyZWN0aW9uCi0gc3RlcCAyOiByZW1vdmUgdGhvc2Ugd2hpY2ggZG9uJ3QgcGFzcyBhIHNpZ25pZmljYW5jZSB0aHJlc2hvbGQKLSBzdGVwIDM6IHJhbmsgYnkgQUlDCkxvYWRpbmcgaW4gYWxsIGV4cGVyaW1lbnRzCmBgYHtyfQpmX2RtcnMgPC0gZnJlYWQoIi9ob21lMS9ORVVSTy9TSEFSRV9ERUNJUEhFUi9ETVJzL1RFUlJFL3NpZy5jcGdzLlRFUlJFLkYuSFQuYW5jZXN0cnkuY3N2IilbYWJzKG1lYW5iZXRhZmMpID49IDAuMDNdCm1fZG1ycyA8LSBmcmVhZCgiL2hvbWUxL05FVVJPL1NIQVJFX0RFQ0lQSEVSL0RNUnMvVEVSUkUvc2lnLmNwZ3MuVEVSUkUuTS5IVC5hbmNlc3RyeS5jc3YiKVthYnMobWVhbmJldGFmYykgPj0gMC4wM10KbWFsZXNfcGQgPC0gcmJpbmRsaXN0KAogIGxhcHBseSgKICAgIFN5cy5nbG9iKCJtYWxlX3RlcnJlX3BkX2ZfKl9kbmFtX2JyZWFrZG93bi50eHQuZ3oiKSwKICAgIGZ1bmN0aW9uKGYpIGZyZWFkKGYsIGZpbGwgPSBUUlVFKSksCiAgZmlsbCA9IFRSVUUKKVtjcGcgJWluJSBtX2RtcnMkY3BnXQptYWxlc19wZFssIGA6PWAoZl9xPXAuYWRqdXN0KGZfcCwgbWV0aG9kID0gIkJIIikpLCBieSA9IGMoIm1vZGVsIiwgImVudiIpXQpmZW1hbGVzX3BkIDwtIHJiaW5kbGlzdCgKICBsYXBwbHkoCiAgICBTeXMuZ2xvYigiZmVtYWxlX3RlcnJlX3BkX2ZfKl9kbmFtX2JyZWFrZG93bi50eHQuZ3oiKSwKICAgIGZ1bmN0aW9uKGYpIGZyZWFkKGYsIGZpbGwgPSBUUlVFKSksCiAgZmlsbCA9IFRSVUUpW2NwZyAlaW4lIGZfZG1ycyRjcGddCmZlbWFsZXNfcGRbLCBgOj1gKGZfcT1wLmFkanVzdChmX3AsIG1ldGhvZCA9ICJCSCIpKSwgYnkgPSBjKCJtb2RlbCIsICJlbnYiKV0KYGBgCgpGaWx0ZXJpbmcgZGF0YSBieToKYGBge3J9Cm1hbGVzX3BkX3NpZyA8LSBtYWxlc19wZFtmX3EgPCAwLjA1XQpmZW1hbGVzX3BkX3NpZyA8LSBmZW1hbGVzX3BkW2ZfcSA8IDAuMDVdCmBgYAphaWMgcmFua2luZwpgYGB7cn0KbWFsZXNfYWljIDwtIG1hbGVzX3BkX3NpZ1ssLlNEW3doaWNoLm1pbihhaWMpXSxieT0iY3BnIl0KZmVtYWxlc19haWMgPC0gZmVtYWxlc19wZF9zaWdbLC5TRFt3aGljaC5taW4oYWljKV0sYnk9ImNwZyJdCmBgYAoKYGBge3J9Cm1hbGVzX2FpY1ttX2RtcnMsb249LihjcGcpXQpmZW1hbGVzX2FpY1tmX2RtcnMsb249LihjcGcpXQptYWxlc19haWMkU2V4IDwtICJNYWxlIgpmZW1hbGVzX2FpYyRTZXggPC0gIkZlbWFsZSIKZ2dwbG90KHJiaW5kKG1hbGVzX2FpYyxmZW1hbGVzX2FpYyksIGFlcyhtb2RlbCxmaWxsPVNleCkpICsKICBnZW9tX2Jhcihwb3NpdGlvbj0iZG9kZ2UiKSsKICBnZW9tX3RleHQoc3RhdD0iY291bnQiLGFlcyhsYWJlbCA9IC4uY291bnQuLikscG9zaXRpb249cG9zaXRpb25fZG9kZ2Uod2lkdGg9MC45KSx2anVzdD0wKSsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9YygiTWFsZSI9ImxpZ2h0Ymx1ZTIiLCJGZW1hbGUiPSJwaW5rIikpKyAKICB0aGVtZV9taW5pbWFsKCkKZl9kbXJzJFNleCA8LSAiRmVtYWxlIgptX2RtcnMkU2V4IDwtICJNYWxlIgphbGxfZG1yIDwtIHJiaW5kKG1fZG1ycyxmX2RtcnMpCmFsbF9haWMgPC0gcmJpbmQobWFsZXNfYWljLCBmZW1hbGVzX2FpYykKdG9fcGxvdCA8LSBhbGxfYWljW2FsbF9kbXIsb249LihjcGcsU2V4KSxub21hdGNoPTBdCmdncGxvdCh0b19wbG90WyFkdXBsaWNhdGVkKHBhc3RlMChkbXIsbW9kZWwsU2V4KSldLCBhZXMobW9kZWwsZmlsbD1TZXgpKSArCiAgZ2VvbV9iYXIocG9zaXRpb249ImRvZGdlIikrCiAgZ2VvbV90ZXh0KHN0YXQ9ImNvdW50IixhZXMobGFiZWwgPSAuLmNvdW50Li4pLHBvc2l0aW9uPXBvc2l0aW9uX2RvZGdlKHdpZHRoPTAuOSksdmp1c3Q9MCkrCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPWMoIk1hbGUiPSJsaWdodGJsdWUyIiwiRmVtYWxlIj0icGluayIpKSsgCiAgdGhlbWVfbWluaW1hbCgpCmBgYAojIyBFZmZlY3Qgc2l6ZSBjb21wYXJpc29ucwpUYWtlIGFsbCBzaWduaWZpY2FudCBtb2RlbHMsIGNvbXBhcmUgRyB2cyBFIHZzIEd4RSBlZmZlY3Qgc2l6ZXM6CmBgYHtyfQptYWxlc19wZF9zaWdbLC4oLk4sdW5pcXVlTihjcGcpKSxieT0ibW9kZWwiXQpmZW1hbGVzX3BkX3NpZ1ssLiguTix1bmlxdWVOKGNwZykpLGJ5PSJtb2RlbCJdCmBgYApgYGB7cn0KcGx0IDwtIFZlbm5EaWFncmFtOjp2ZW5uLmRpYWdyYW0oCiAgbGFwcGx5KHNwbGl0KG1hbGVzX3BkX3NpZyxieT0ibW9kZWwiKSxmdW5jdGlvbihkdClkdCRjcGcpLAogIGZpbGVuYW1lPU5VTEwKKQpncmlkOjpncmlkLm5ld3BhZ2UoKQpncmlkOjpncmlkLmRyYXcocGx0KQoKcGx0IDwtIFZlbm5EaWFncmFtOjp2ZW5uLmRpYWdyYW0oCiAgbGFwcGx5KHNwbGl0KGZlbWFsZXNfcGRfc2lnLGJ5PSJtb2RlbCIpLGZ1bmN0aW9uKGR0KWR0JGNwZyksCiAgZmlsZW5hbWU9TlVMTAopCmdyaWQ6OmdyaWQubmV3cGFnZSgpCmdyaWQ6OmdyaWQuZHJhdyhwbHQpCgpwbHQgPC0gVmVubkRpYWdyYW06OnZlbm4uZGlhZ3JhbSgKICBsYXBwbHkoc3BsaXQobWFsZXNfcGRfc2lnLGJ5PSJtb2RlbCIpLGZ1bmN0aW9uKGR0KWR0JFNOUCksCiAgZmlsZW5hbWU9TlVMTAopCmdyaWQ6OmdyaWQubmV3cGFnZSgpCmdyaWQ6OmdyaWQuZHJhdyhwbHQpCgpwbHQgPC0gVmVubkRpYWdyYW06OnZlbm4uZGlhZ3JhbSgKICBsYXBwbHkoc3BsaXQoZmVtYWxlc19wZF9zaWcsYnk9Im1vZGVsIiksZnVuY3Rpb24oZHQpZHQkU05QKSwKICBmaWxlbmFtZT1OVUxMCikKZ3JpZDo6Z3JpZC5uZXdwYWdlKCkKZ3JpZDo6Z3JpZC5kcmF3KHBsdCkKYGBgCiMjIEVmZmVjdHMgaW4gR3hFIHNldApgYGB7cn0KbGlicmFyeShnZ3B1YnIpCmd4ZV9tYWxlc19wZCA8LSBtYWxlc19wZFttb2RlbD09Ikd4RSJdCmd4ZV9tYWxlc19wZFssIGA6PWAoR19xPXAuYWRqdXN0KEdwLG1ldGhvZD0iZmRyIiksRV9xPXAuYWRqdXN0KEVwLG1ldGhvZD0iZmRyIiksR3hFX3E9cC5hZGp1c3QoR3hFcCxtZXRob2Q9ImZkciIpKSxieT1jKCJlbnYiKV0KZ3hlX21hbGVzX3BkIDwtIGd4ZV9tYWxlc19wZFtmX3EgPCAwLjA1XQoKZ3hlX21hbGVzX3BkWywuKHVuaXF1ZU4oY3BnW0dfcSA8IDAuMDVdKSx1bmlxdWVOKGNwZ1tFX3EgPCAwLjA1XSksdW5pcXVlTihjcGdbR3hFX3EgPCAwLjA1XSkpXQpneGVfbWFsZV9zaWdfR19jb3VudCA8LSB0YWJsZShneGVfbWFsZXNfcGRbR19xIDwgMC4wNV1bLC4oY3BnLGVudildKSAjIGNvdW50cyBvZiBTTlBzIHdpdGggc2lnbmlmaWNhbnQgZWZmZWN0cyBwZXIgY3BnLGVudgoKZ3hlX21hbGVzX3BkW0dfcSA8IDAuMDVdWyFkdXBsaWNhdGVkKGNwZyldCnNpZ19tYWxlX2UgPC0gZ3hlX21hbGVzX3BkW0VfcSA8IDAuMDVdCnNpZ19tYWxlX2VbIWR1cGxpY2F0ZWQoc2lnX21hbGVfZVssLihlbnYsY3BnKV0pXQoKZ3hlX2ZlbWFsZXNfcGQgPC0gZmVtYWxlc19wZFttb2RlbD09Ikd4RSJdCmd4ZV9mZW1hbGVzX3BkWywgYDo9YChHX3E9cC5hZGp1c3QoR3AsbWV0aG9kPSJmZHIiKSxFX3E9cC5hZGp1c3QoRXAsbWV0aG9kPSJmZHIiKSxHeEVfcT1wLmFkanVzdChHeEVwLG1ldGhvZD0iZmRyIikpLGJ5PWMoImVudiIpXQpneGVfZmVtYWxlc19wZCA8LSBneGVfZmVtYWxlc19wZFtmX3EgPCAwLjA1XQoKZ3hlX2ZlbWFsZXNfcGRbLC4odW5pcXVlTihjcGdbR19xIDwgMC4wNV0pLHVuaXF1ZU4oY3BnW0VfcSA8IDAuMDVdKSx1bmlxdWVOKGNwZ1tHeEVfcSA8IDAuMDVdKSldCmd4ZV9mZW1hbGVfc2lnX0dfY291bnQgPC0gdGFibGUoZ3hlX2ZlbWFsZXNfcGRbR19xIDwgMC4wNV1bLC4oY3BnLGVudildKSAjIGNvdW50cyBvZiBTTlBzIHdpdGggc2lnbmlmaWNhbnQgZWZmZWN0cyBwZXIgY3BnLGVudgoKZ3hlX2ZlbWFsZXNfcGRbR19xIDwgMC4wNV1bIWR1cGxpY2F0ZWQoY3BnKV0KZ3hlX2ZlbWFsZXNfcGRbRV9xIDwgMC4wNV0KCmBgYApgYGB7cn0KZ2dib3hwbG90KAogIG1lbHQoZ3hlX21hbGVzX3BkWywuU0Rbd2hpY2gubWluKGFpYyldLGJ5PSJjcGciXVssLihHPWFicyhHZXN0KSxFPWFicyhFZXN0KSxHeEU9YWJzKEd4RWVzdCkpXSx2YWx1ZS5uYW1lPSJFc3RpbWF0ZSIsdmFyaWFibGUubmFtZSA9ICJDb2VmZmljaWVudCIpLHggPSAiQ29lZmZpY2llbnQiLHk9IkVzdGltYXRlIixvdXRsaWVyLnNoYXBlID0gTkEsZmlsbCA9ICJsaWdodGJsdWUyIikgKwogIGNvb3JkX2NhcnRlc2lhbih5bGltPWMoMCwxKSkgKwogIHN0YXRfY29tcGFyZV9tZWFucygKICAgIHBhaXJlZD1UUlVFLGxhYmVsLnkgPSAtMC41LG1ldGhvZC5hcmdzID0gbGlzdChhbHRlcm5hdGl2ZSA9ImciKSx0aXAubGVuZ3RoID0gMC4wMSwgc3RlcC5pbmNyZWFzZSA9IDAuMDEyLAogICAgY29tcGFyaXNvbnMgPSBsaXN0KGMoIkciLCJFIiksYygiRyIsIkd4RSIpLGMoIkUiLCJHeEUiKSkpCmNvbXBhcmVfbWVhbnMoCiAgRXN0aW1hdGV+Q29lZmZpY2llbnQscGFpcmVkPVRSVUUsCiAgbWVsdChneGVfbWFsZXNfcGRbLC5TRFt3aGljaC5taW4oYWljKV0sYnk9ImNwZyJdWywuKEc9YWJzKEdlc3QpLEU9YWJzKEVlc3QpLEd4RT1hYnMoR3hFZXN0KSldLHZhbHVlLm5hbWU9IkVzdGltYXRlIix2YXJpYWJsZS5uYW1lID0gIkNvZWZmaWNpZW50IiksCiAgYWx0ZXJuYXRpdmU9ImwiLG1ldGhvZCA9ICJ3aWxjb3giKSAKa3J1c2thbC50ZXN0KG1lbHQoZ3hlX21hbGVzX3BkWywuU0Rbd2hpY2gubWluKGFpYyldLGJ5PSJjcGciXVssLihHPWFicyhHZXN0KSxFPWFicyhFZXN0KSxHeEU9YWJzKEd4RWVzdCkpXSx2YWx1ZS5uYW1lPSJFc3RpbWF0ZSIsdmFyaWFibGUubmFtZSA9ICJDb2VmZmljaWVudCIpKQoKZ2dib3hwbG90KAogIG1lbHQoZ3hlX2ZlbWFsZXNfcGRbLC5TRFt3aGljaC5taW4oYWljKV0sYnk9ImNwZyJdWywuKEc9YWJzKEdlc3QpLEU9YWJzKEVlc3QpLEd4RT1hYnMoR3hFZXN0KSldLHZhbHVlLm5hbWU9IkVzdGltYXRlIix2YXJpYWJsZS5uYW1lID0gIkNvZWZmaWNpZW50IikseCA9ICJDb2VmZmljaWVudCIseT0iRXN0aW1hdGUiLG91dGxpZXIuc2hhcGU9TkEsZmlsbCA9ICJwaW5rIikgKwogIGNvb3JkX2NhcnRlc2lhbih5bGltPWMoMCwxLjUpKSArCiAgc3RhdF9jb21wYXJlX21lYW5zKHBhaXJlZD1UUlVFLGxhYmVsLnkgPSAtMTQuLG1ldGhvZC5hcmdzID0gbGlzdChhbHRlcm5hdGl2ZSA9ImwiKSx0aXAubGVuZ3RoID0gMC4wMDA1LHN0ZXAuaW5jcmVhc2U9MC4wMDA2LGNvbXBhcmlzb25zID0gbGlzdChjKCJHIiwiRSIpLGMoIkciLCJHeEUiKSxjKCJFIiwiR3hFIikpKQpjb21wYXJlX21lYW5zKEVzdGltYXRlfkNvZWZmaWNpZW50LHBhaXJlZD1UUlVFLG1lbHQoZ3hlX2ZlbWFsZXNfcGRbLC5TRFt3aGljaC5taW4oYWljKV0sYnk9ImNwZyJdWywuKEc9YWJzKEdlc3QpLEU9YWJzKEVlc3QpLEd4RT1hYnMoR3hFZXN0KSldLHZhbHVlLm5hbWU9IkVzdGltYXRlIix2YXJpYWJsZS5uYW1lID0gIkNvZWZmaWNpZW50IiksYWx0ZXJuYXRpdmU9ImciKSAKa3J1c2thbC50ZXN0KG1lbHQoZ3hlX2ZlbWFsZXNfcGRbLC5TRFt3aGljaC5taW4oYWljKV0sYnk9ImNwZyJdWywuKEc9YWJzKEdlc3QpLEU9YWJzKEVlc3QpLEd4RT1hYnMoR3hFZXN0KSldLHZhbHVlLm5hbWU9IkVzdGltYXRlIix2YXJpYWJsZS5uYW1lID0gIkNvZWZmaWNpZW50IikpCmBgYAoKIyMjIHNjYWxlIG9mIGRpZmZlcmVuY2VzIHBlciBtb2RlbCBAVE9ETyBHeEUKCmBgYHtyfQpneGVfbWFsZXNfcGRbLGA6PWAoWmdlID0gKGFicyhHZXN0KSAtIGFicyhFZXN0KSkvc3FydChHc2VeMiArIEVzZV4yKSldCmd4ZV9tYWxlc19wZFssYDo9YChacCA9IDIqKHBub3JtKC1hYnMoWmdlKSkpKV0KZ3hlX21hbGVzX3BkWyxgOj1gKFpfcSA9IHAuYWRqdXN0KFpwLG1ldGhvZD0iZmRyIikpLGJ5PWMoImVudiIpXQoKZ3hlX21hbGVzX3BkWyxgOj1gKFpneGUgPSAoYWJzKEdlc3QpIC0gYWJzKEd4RWVzdCkpL3NxcnQoR3NlXjIgKyBHeEVzZV4yKSldCmd4ZV9tYWxlc19wZFssYDo9YChaZ3hlcCA9IDIqKHBub3JtKC1hYnMoWmd4ZSkpKSldCmd4ZV9tYWxlc19wZFssYDo9YChaZ3hlX3EgPSBwLmFkanVzdChaZ3hlcCxtZXRob2Q9ImZkciIpKSxieT1jKCJlbnYiKV0KCmd4ZV9tYWxlc19wZFssYDo9YChaZWd4ZSA9IChhYnMoRWVzdCkgLSBhYnMoR3hFZXN0KSkvc3FydChFc2VeMiArIEd4RXNlXjIpKV0KZ3hlX21hbGVzX3BkWyxgOj1gKFplZ3hlcCA9IDIqKHBub3JtKC1hYnMoWmVneGUpKSkpXQpneGVfbWFsZXNfcGRbLGA6PWAoWmVneGVfcSA9IHAuYWRqdXN0KFplZ3hlcCxtZXRob2Q9ImZkciIpKSxieT1jKCJlbnYiKV0KCmd4ZV9mZW1hbGVzX3BkWyxgOj1gKFpnZSA9IChhYnMoR2VzdCkgLSBhYnMoRWVzdCkpL3NxcnQoR3NlXjIgKyBFc2VeMikpXQpneGVfZmVtYWxlc19wZFssYDo9YChacCA9IDIqKHBub3JtKC1hYnMoWmdlKSkpKV0KZ3hlX2ZlbWFsZXNfcGRbLGA6PWAoWl9xID0gcC5hZGp1c3QoWnAsbWV0aG9kPSJmZHIiKSksYnk9YygiZW52IildCgpneGVfZmVtYWxlc19wZFssYDo9YChaZ3hlID0gKGFicyhHZXN0KSAtIGFicyhHeEVlc3QpKS9zcXJ0KEdzZV4yICsgR3hFc2VeMikpXQpneGVfZmVtYWxlc19wZFssYDo9YChaZ3hlcCA9IDIqKHBub3JtKC1hYnMoWmd4ZSkpKSldCmd4ZV9mZW1hbGVzX3BkWyxgOj1gKFpneGVfcSA9IHAuYWRqdXN0KFpneGVwLG1ldGhvZD0iZmRyIikpLGJ5PWMoImVudiIpXQoKZ3hlX2ZlbWFsZXNfcGRbLGA6PWAoWmVneGUgPSAoYWJzKEVlc3QpIC0gYWJzKEd4RWVzdCkpL3NxcnQoRXNlXjIgKyBHeEVzZV4yKSldCmd4ZV9mZW1hbGVzX3BkWyxgOj1gKFplZ3hlcCA9IDIqKHBub3JtKC1hYnMoWmVneGUpKSkpXQpneGVfZmVtYWxlc19wZFssYDo9YChaZWd4ZV9xID0gcC5hZGp1c3QoWmVneGVwLG1ldGhvZD0iZmRyIikpLGJ5PWMoImVudiIpXQpgYGAKCmBgYHtyfQpneGVfbWFsZXNfcGRbWl9xIDwgMC4wNSwuKGhpdHM9dW5pcXVlTihjcGcpLHBhc3RlMCh1bmlxdWUoY3BnKSxjb2xsYXBzZT0iLCIpKSxieT0iZW52Il0KZ3hlX2ZlbWFsZXNfcGRbWl9xIDwgMC4wNSwuKGhpdHM9dW5pcXVlTihjcGcpLHBhc3RlMCh1bmlxdWUoY3BnKSxjb2xsYXBzZT0iLCIpKSxieT0iZW52Il0KZ3hlX21hbGVzX3BkW1pfcSA8IDAuMDVdCmd4ZV9mZW1hbGVzX3BkW1pfcSA8IDAuMDVdCnVuaXF1ZShneGVfbWFsZXNfcGRbWl9xIDwgMC4wNV0kY3BnKQp1bmlxdWUoZ3hlX2ZlbWFsZXNfcGRbWl9xIDwgMC4wNV0kY3BnKQptX2RtcnNbY3BnICVpbiUgdW5pcXVlKGd4ZV9tYWxlc19wZFtaX3EgPCAwLjA1XSRjcGcpXQpmX2RtcnNbY3BnICVpbiUgdW5pcXVlKGd4ZV9mZW1hbGVzX3BkW1pfcSA8IDAuMDVdJGNwZyldCmBgYAoKYGBge3J9Cmd4ZV9tYWxlc19wZFtaZ3hlX3EgPCAwLjA1LC4oaGl0cz11bmlxdWVOKGNwZykscGFzdGUwKHVuaXF1ZShjcGcpLGNvbGxhcHNlPSIsIikpLGJ5PSJlbnYiXQpneGVfZmVtYWxlc19wZFtaZ3hlX3EgPCAwLjA1LC4oaGl0cz11bmlxdWVOKGNwZykscGFzdGUwKHVuaXF1ZShjcGcpLGNvbGxhcHNlPSIsIikpLGJ5PSJlbnYiXQpneGVfbWFsZXNfcGRbWmd4ZV9xIDwgMC4wNV0KZ3hlX2ZlbWFsZXNfcGRbWmd4ZV9xIDwgMC4wNV0KdW5pcXVlKGd4ZV9tYWxlc19wZFtaZ3hlX3EgPCAwLjA1XSRjcGcpCnVuaXF1ZShneGVfZmVtYWxlc19wZFtaZ3hlX3EgPCAwLjA1XSRjcGcpCm1fZG1yc1tjcGcgJWluJSB1bmlxdWUoZ3hlX21hbGVzX3BkW1pneGVfcSA8IDAuMDVdJGNwZyldCmZfZG1yc1tjcGcgJWluJSB1bmlxdWUoZ3hlX2ZlbWFsZXNfcGRbWmd4ZV9xIDwgMC4wNV0kY3BnKV0KYGBgCmBgYHtyfQpneGVfbWFsZXNfcGRbWmVneGVfcSA8IDAuMDUsLihoaXRzPXVuaXF1ZU4oY3BnKSxwYXN0ZTAodW5pcXVlKGNwZyksY29sbGFwc2U9IiwiKSksYnk9ImVudiJdCmd4ZV9mZW1hbGVzX3BkW1plZ3hlX3EgPCAwLjA1LC4oaGl0cz11bmlxdWVOKGNwZykscGFzdGUwKHVuaXF1ZShjcGcpLGNvbGxhcHNlPSIsIikpLGJ5PSJlbnYiXQpneGVfbWFsZXNfcGRbWmVneGVfcSA8IDAuMDVdCmd4ZV9mZW1hbGVzX3BkW1plZ3hlX3EgPCAwLjA1XQp1bmlxdWUoZ3hlX21hbGVzX3BkW1plZ3hlX3EgPCAwLjA1XSRjcGcpCnVuaXF1ZShneGVfZmVtYWxlc19wZFtaZWd4ZV9xIDwgMC4wNV0kY3BnKQptX2RtcnNbY3BnICVpbiUgdW5pcXVlKGd4ZV9tYWxlc19wZFtaZWd4ZV9xIDwgMC4wNV0kY3BnKV0KZl9kbXJzW2NwZyAlaW4lIHVuaXF1ZShneGVfZmVtYWxlc19wZFtaZWd4ZV9xIDwgMC4wNV0kY3BnKV0KYGBgCgpgYGB7cn0KZ2dib3hwbG90KHJiaW5kbGlzdChsaXN0KE1hbGU9Z3hlX21hbGVzX3BkWywuKFpnZSldLEZlbWFsZT1neGVfZmVtYWxlc19wZFssLihaZ2UpXSksaWRjb2w9IlNleCIpLHg9IlNleCIseT0iWmdlIixmaWxsPSJTZXgiKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPWMoTWFsZSA9ICJsaWdodGJsdWUyIiwgRmVtYWxlPSJwaW5rIikpICsgCiAgc3RhdF9jb21wYXJlX21lYW5zKCkKCmdnYm94cGxvdChyYmluZGxpc3QobGlzdChNYWxlPWd4ZV9tYWxlc19wZFssLihaZ3hlKV0sRmVtYWxlPWd4ZV9mZW1hbGVzX3BkWywuKFpneGUpXSksaWRjb2w9IlNleCIpLHg9IlNleCIseT0iWmd4ZSIsZmlsbD0iU2V4IikgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz1jKE1hbGUgPSAibGlnaHRibHVlMiIsIEZlbWFsZT0icGluayIpKSArIAogIHN0YXRfY29tcGFyZV9tZWFucygpCgpnZ2JveHBsb3QocmJpbmRsaXN0KGxpc3QoTWFsZT1neGVfbWFsZXNfcGRbLC4oWmVneGUpXSxGZW1hbGU9Z3hlX2ZlbWFsZXNfcGRbLC4oWmVneGUpXSksaWRjb2w9IlNleCIpLHg9IlNleCIseT0iWmVneGUiLGZpbGw9IlNleCIpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9YyhNYWxlID0gImxpZ2h0Ymx1ZTIiLCBGZW1hbGU9InBpbmsiKSkgKyAKICBzdGF0X2NvbXBhcmVfbWVhbnMoKQpgYGAKCg==